#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""项目浏览器组件"""

import os
from PyQt5.QtWidgets import (
    QWidget, QVBoxLayout, QTreeWidget, QTreeWidgetItem,
    QMenu, QAction, QFileDialog, QInputDialog, QMessageBox,
    QHeaderView
)
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot, QFileInfo
from PyQt5.QtGui import QFont, QColor, QBrush, QIcon


class ProjectExplorer(QWidget):
    """项目浏览器组件"""
    
    # 文件打开信号
    file_opened = pyqtSignal(str)  # 传递文件路径
    
    # 项目创建/打开信号
    project_changed = pyqtSignal(str)  # 传递项目路径
    
    def __init__(self, parent=None):
        """初始化项目浏览器"""
        super().__init__(parent)
        
        # 设置窗口属性
        self.setWindowTitle("项目浏览器")
        self.setMinimumWidth(180)
        
        # 当前项目路径
        self.current_project_path = None
        
        # 创建主布局
        main_layout = QVBoxLayout(self)
        
        # 创建文件树
        self.file_tree = QTreeWidget()
        self.file_tree.setHeaderHidden(True)  # 隐藏表头
        self.file_tree.setAlternatingRowColors(True)
        self.file_tree.setContextMenuPolicy(Qt.CustomContextMenu)
        
        # 添加到主布局
        main_layout.addWidget(self.file_tree)
        
        # 设置信号和槽
        self.setup_connections()
        
        # 创建上下文菜单
        self.create_context_menu()
        
        # 初始状态显示"无项目打开"的提示
        self.show_no_project_message()
    
    def setup_connections(self):
        """设置信号和槽的连接"""
        # 连接项目点击信号
        self.file_tree.itemClicked.connect(self.on_item_clicked)
        
        # 连接项目双击信号
        self.file_tree.itemDoubleClicked.connect(self.on_item_double_clicked)
        
        # 连接上下文菜单信号
        self.file_tree.customContextMenuRequested.connect(self.show_context_menu)
    
    def create_context_menu(self):
        """创建上下文菜单"""
        self.context_menu = QMenu(self)
        
        # 添加新建文件菜单项
        self.new_file_action = QAction("新建文件", self)
        self.new_file_action.triggered.connect(self.new_file)
        self.context_menu.addAction(self.new_file_action)
        
        # 添加新建文件夹菜单项
        self.new_folder_action = QAction("新建文件夹", self)
        self.new_folder_action.triggered.connect(self.new_folder)
        self.context_menu.addAction(self.new_folder_action)
        
        self.context_menu.addSeparator()
        
        # 添加打开文件菜单项
        self.open_file_action = QAction("打开文件", self)
        self.open_file_action.triggered.connect(self.open_file)
        self.context_menu.addAction(self.open_file_action)
        
        # 添加打开文件夹菜单项
        self.open_folder_action = QAction("打开文件夹", self)
        self.open_folder_action.triggered.connect(self.open_folder)
        self.context_menu.addAction(self.open_folder_action)
        
        self.context_menu.addSeparator()
        
        # 添加重命名菜单项
        self.rename_action = QAction("重命名", self)
        self.rename_action.triggered.connect(self.rename_item)
        self.context_menu.addAction(self.rename_action)
        
        # 添加删除菜单项
        self.delete_action = QAction("删除", self)
        self.delete_action.triggered.connect(self.delete_item)
        self.context_menu.addAction(self.delete_action)
    
    def show_no_project_message(self):
        """显示"无项目打开"的提示"""
        self.file_tree.clear()
        
        # 创建提示节点
        no_project_item = QTreeWidgetItem(["无项目打开"])
        no_project_item.setFlags(no_project_item.flags() & ~Qt.ItemIsEditable)
        no_project_item.setForeground(0, QBrush(QColor(128, 128, 128)))
        
        self.file_tree.addTopLevelItem(no_project_item)
    
    def create_new_project(self, project_path):
        """创建新项目"""
        try:
            # 检查路径是否存在
            if not os.path.exists(project_path):
                os.makedirs(project_path)
            
            # 设置当前项目路径
            self.current_project_path = project_path
            
            # 刷新项目树
            self.refresh_project_tree()
            
            # 发送项目改变信号
            self.project_changed.emit(project_path)
            
            return True
        except Exception as e:
            QMessageBox.critical(self, "错误", f"无法创建项目: {str(e)}")
            return False
    
    def open_project(self, project_path):
        """打开现有项目"""
        try:
            # 检查路径是否存在且是目录
            if not os.path.exists(project_path) or not os.path.isdir(project_path):
                QMessageBox.warning(self, "警告", f"无效的项目路径: {project_path}")
                return False
            
            # 设置当前项目路径
            self.current_project_path = project_path
            
            # 刷新项目树
            self.refresh_project_tree()
            
            # 发送项目改变信号
            self.project_changed.emit(project_path)
            
            return True
        except Exception as e:
            QMessageBox.critical(self, "错误", f"无法打开项目: {str(e)}")
            return False
    
    def close_project(self):
        """关闭当前项目"""
        self.current_project_path = None
        self.show_no_project_message()
        self.project_changed.emit("")
    
    def refresh_project_tree(self):
        """刷新项目树"""
        if not self.current_project_path:
            self.show_no_project_message()
            return
        
        # 清空文件树
        self.file_tree.clear()
        
        # 获取项目名称
        project_name = os.path.basename(self.current_project_path)
        
        # 创建项目根节点
        project_root = QTreeWidgetItem([project_name])
        project_root.setData(0, Qt.UserRole, self.current_project_path)
        project_root.setFlags(project_root.flags() | Qt.ItemIsEditable)
        
        # 设置项目根节点字体为粗体
        font = project_root.font(0)
        font.setBold(True)
        project_root.setFont(0, font)
        
        # 添加到文件树
        self.file_tree.addTopLevelItem(project_root)
        
        # 递归添加子文件和文件夹
        self.add_files_and_folders(self.current_project_path, project_root)
        
        # 展开项目根节点
        project_root.setExpanded(True)
    
    def add_files_and_folders(self, path, parent_item):
        """递归添加文件和文件夹"""
        try:
            # 获取路径下的所有文件和文件夹
            items = os.listdir(path)
            
            # 分离文件夹和文件
            folders = []
            files = []
            
            for item in items:
                item_path = os.path.join(path, item)
                if os.path.isdir(item_path):
                    folders.append(item)
                else:
                    files.append(item)
            
            # 按名称排序
            folders.sort()
            files.sort()
            
            # 添加文件夹
            for folder in folders:
                folder_path = os.path.join(path, folder)
                
                # 创建文件夹节点
                folder_item = QTreeWidgetItem([folder])
                folder_item.setData(0, Qt.UserRole, folder_path)
                folder_item.setFlags(folder_item.flags() | Qt.ItemIsEditable)
                
                # 添加到父节点
                parent_item.addChild(folder_item)
                
                # 递归添加子文件和文件夹
                self.add_files_and_folders(folder_path, folder_item)
            
            # 添加文件
            for file in files:
                file_path = os.path.join(path, file)
                
                # 创建文件节点
                file_item = QTreeWidgetItem([file])
                file_item.setData(0, Qt.UserRole, file_path)
                file_item.setFlags(file_item.flags() | Qt.ItemIsEditable)
                
                # 添加到父节点
                parent_item.addChild(file_item)
        except Exception as e:
            print(f"无法添加文件和文件夹: {str(e)}")
    
    def on_item_clicked(self, item, column):
        """处理项目点击事件"""
        # 获取项目路径
        item_path = item.data(0, Qt.UserRole)
        
        # 可以在这里添加选中文件或文件夹的处理逻辑
    
    def on_item_double_clicked(self, item, column):
        """处理项目双击事件"""
        # 获取项目路径
        item_path = item.data(0, Qt.UserRole)
        
        if not item_path:
            return
        
        # 如果是文件，打开文件
        if os.path.isfile(item_path):
            self.open_file_in_editor(item_path)
        # 如果是文件夹，切换展开/折叠状态
        elif os.path.isdir(item_path):
            item.setExpanded(not item.isExpanded())
    
    def show_context_menu(self, position):
        """显示上下文菜单"""
        # 获取当前选中的项目
        selected_items = self.file_tree.selectedItems()
        
        if not selected_items or not self.current_project_path:
            return
        
        # 根据选中的项目类型调整菜单项
        item = selected_items[0]
        item_path = item.data(0, Qt.UserRole)
        
        if os.path.isdir(item_path):
            # 文件夹：显示所有菜单项
            self.new_file_action.setVisible(True)
            self.new_folder_action.setVisible(True)
            self.open_file_action.setVisible(False)
            self.open_folder_action.setVisible(True)
        else:
            # 文件：隐藏新建文件和文件夹菜单项
            self.new_file_action.setVisible(False)
            self.new_folder_action.setVisible(False)
            self.open_file_action.setVisible(True)
            self.open_folder_action.setVisible(False)
        
        # 显示上下文菜单
        self.context_menu.exec_(self.file_tree.mapToGlobal(position))
    
    def new_file(self):
        """新建文件"""
        # 获取当前选中的文件夹
        selected_items = self.file_tree.selectedItems()
        
        if not selected_items:
            return
        
        parent_item = selected_items[0]
        parent_path = parent_item.data(0, Qt.UserRole)
        
        # 如果选中的不是文件夹，使用其父文件夹
        if not os.path.isdir(parent_path):
            parent_item = parent_item.parent()
            if not parent_item:
                return
            parent_path = parent_item.data(0, Qt.UserRole)
        
        # 显示文件名输入对话框
        file_name, ok = QInputDialog.getText(self, "新建文件", "请输入文件名:")
        
        if ok and file_name:
            file_path = os.path.join(parent_path, file_name)
            
            # 检查文件是否已存在
            if os.path.exists(file_path):
                QMessageBox.warning(self, "警告", "文件已存在")
                return
            
            try:
                # 创建空文件
                with open(file_path, 'w', encoding='utf-8') as f:
                    pass
                
                # 刷新项目树
                self.refresh_project_tree()
                
                # 打开新创建的文件
                self.open_file_in_editor(file_path)
            except Exception as e:
                QMessageBox.critical(self, "错误", f"无法创建文件: {str(e)}")
    
    def new_folder(self):
        """新建文件夹"""
        # 获取当前选中的文件夹
        selected_items = self.file_tree.selectedItems()
        
        if not selected_items:
            return
        
        parent_item = selected_items[0]
        parent_path = parent_item.data(0, Qt.UserRole)
        
        # 如果选中的不是文件夹，使用其父文件夹
        if not os.path.isdir(parent_path):
            parent_item = parent_item.parent()
            if not parent_item:
                return
            parent_path = parent_item.data(0, Qt.UserRole)
        
        # 显示文件夹名输入对话框
        folder_name, ok = QInputDialog.getText(self, "新建文件夹", "请输入文件夹名:")
        
        if ok and folder_name:
            folder_path = os.path.join(parent_path, folder_name)
            
            # 检查文件夹是否已存在
            if os.path.exists(folder_path):
                QMessageBox.warning(self, "警告", "文件夹已存在")
                return
            
            try:
                # 创建文件夹
                os.makedirs(folder_path)
                
                # 刷新项目树
                self.refresh_project_tree()
            except Exception as e:
                QMessageBox.critical(self, "错误", f"无法创建文件夹: {str(e)}")
    
    def open_file(self):
        """打开文件"""
        # 获取当前选中的文件
        selected_items = self.file_tree.selectedItems()
        
        if not selected_items:
            return
        
        item = selected_items[0]
        file_path = item.data(0, Qt.UserRole)
        
        # 检查是否是文件
        if os.path.isfile(file_path):
            self.open_file_in_editor(file_path)
    
    def open_folder(self):
        """打开文件夹"""
        # 获取当前选中的文件夹
        selected_items = self.file_tree.selectedItems()
        
        if not selected_items:
            return
        
        item = selected_items[0]
        folder_path = item.data(0, Qt.UserRole)
        
        # 检查是否是文件夹
        if os.path.isdir(folder_path):
            # 切换展开/折叠状态
            item.setExpanded(not item.isExpanded())
    
    def rename_item(self):
        """重命名项目"""
        # 获取当前选中的项目
        selected_items = self.file_tree.selectedItems()
        
        if not selected_items or len(selected_items) > 1:
            return
        
        item = selected_items[0]
        item_path = item.data(0, Qt.UserRole)
        
        # 显示重命名对话框
        new_name, ok = QInputDialog.getText(self, "重命名", "请输入新名称:", text=os.path.basename(item_path))
        
        if ok and new_name and new_name != os.path.basename(item_path):
            # 获取父目录
            parent_dir = os.path.dirname(item_path)
            new_path = os.path.join(parent_dir, new_name)
            
            # 检查新名称是否已存在
            if os.path.exists(new_path):
                QMessageBox.warning(self, "警告", "名称已存在")
                return
            
            try:
                # 重命名文件或文件夹
                os.rename(item_path, new_path)
                
                # 刷新项目树
                self.refresh_project_tree()
            except Exception as e:
                QMessageBox.critical(self, "错误", f"无法重命名: {str(e)}")
    
    def delete_item(self):
        """删除项目"""
        # 获取当前选中的项目
        selected_items = self.file_tree.selectedItems()
        
        if not selected_items:
            return
        
        # 确认删除
        reply = QMessageBox.question(self, "确认删除", 
                                     f"确定要删除选中的 {len(selected_items)} 个项目吗？",
                                     QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        
        if reply == QMessageBox.Yes:
            for item in selected_items:
                item_path = item.data(0, Qt.UserRole)
                
                # 不允许删除项目根目录
                if item_path == self.current_project_path:
                    QMessageBox.warning(self, "警告", "不能删除项目根目录")
                    continue
                
                try:
                    # 删除文件或文件夹
                    if os.path.isfile(item_path):
                        os.remove(item_path)
                    elif os.path.isdir(item_path):
                        import shutil
                        shutil.rmtree(item_path)
                except Exception as e:
                    QMessageBox.critical(self, "错误", f"无法删除 '{os.path.basename(item_path)}': {str(e)}")
            
            # 刷新项目树
            self.refresh_project_tree()
    
    def open_file_in_editor(self, file_path):
        """在编辑器中打开文件"""
        # 发送文件打开信号
        self.file_opened.emit(file_path)
    
    def get_current_project_path(self):
        """获取当前项目路径"""
        return self.current_project_path